# !/usr/bin/env python
# -*-coding:utf-8 -*-
"""
# File       : app_context.py
# Time       ：2023/7/31 21:45
# Author     ：Y-aong
# version    ：python 3.7
# Description：
    orderlines app context
"""
import json
from typing import List, Any

from apscheduler.jobstores import redis

from conf.config import OrderLinesConfig, Redis
from public.logger import logger


class RedisContext:
    """使用redis hash作为缓存"""

    def __init__(self):
        self.redis = redis.Redis(host=Redis.host, port=Redis.port, db=Redis.db, decode_responses=True)
        self.name = None

    def get(self, key: str, default: Any = None):
        response = self.redis.hget(self.name, key)
        return json.loads(response) if response else default

    def pop(self, key: str, default: Any = None):
        response = self.get(key, default)
        self.redis.hdel(self.name, *[key])
        return response

    def setdefault(self, name, default: dict):
        self.name = f'orderlines:process:{name}'
        if isinstance(default, dict):
            default = json.dumps(default)
        if self.contains(name):
            self.redis.hdel(self.name, name)

        self.redis.hset(self.name, name, default)

    def contains(self, name):
        response = self.redis.hget(self.name, name)
        return response is not None


class AppContext(object):
    def __init__(self, task_patten=None):
        if not task_patten:
            self.task_pattern = OrderLinesConfig.task_pattern
        else:
            self.task_pattern = task_patten
        if self.task_pattern == 'local':
            self.context = self.__dict__
        else:
            self.context = RedisContext()

    def get(self, name, default=None):
        return self.context.get(name, default)

    def pop(self, name, default):
        return self.context.pop(name, default)

    def setdefault(self, name, default=None):
        return self.context.setdefault(name, default)

    def get_process_info(self, process_instance_id: str, default=None) -> dict:
        process_instance_info = self.get(process_instance_id, {})
        return process_instance_info.get('process_info', default)

    def get_process_item(self, process_instance_id: str, item_name: str, default=None) -> any:
        process_info = self.get_process_info(process_instance_id)
        return process_info.get(item_name) if process_info else default

    def get_process_items(self, process_instance_id: str, *args) -> dict:
        process_items = dict()
        process_info = self.get_process_info(process_instance_id)
        for item_name in args:
            item = process_info.get(item_name, None)
            if process_info and item:
                process_items.setdefault(item_name, item)
        return process_items

    def get_task_nodes(self, process_instance_id) -> List[dict]:
        process_instance_info = self.context.get(process_instance_id, {})
        return process_instance_info.get('task_nodes', {})

    def get_task_node(self, process_instance_id: str, task_id: str, default=None) -> dict:
        """获取当前正在运行的任务节点"""
        process_instance_info = self.context.get(process_instance_id, {})
        task_nodes = process_instance_info.get('task_nodes', {})
        for task_node in task_nodes:
            if task_node.get('task_id') == task_id:
                return task_node
        logger.warn(f'by process_instance_id:{process_instance_id}, task_id:{task_id} can not find task node')
        return default

    def get_task_node_item(
            self,
            process_instance_id: str,
            task_id: str,
            item_name: str,
            default=None
    ) -> Any:
        task_node = self.get_task_node(process_instance_id, task_id)
        item = task_node.get(item_name)
        return item if item else default

    def get_task_node_items(self, process_instance_id: str, task_id: str, *args) -> dict:
        task_node = self.get_task_node(process_instance_id, task_id)
        node_items = dict()
        for item_name in args:
            if task_node and task_node.get(item_name):
                node_items.setdefault(item_name, task_node.get(item_name))
        return node_items

    def __contains__(self, item):
        if self.task_pattern == 'local':
            return item in self.context
        else:
            return self.context.contains(item)
